﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Experimentor.CheckResponsiveness
{
    class CheckResponsivenessWorker : BackgroundWorker
    {
        public const int STAGE_BEST = 1;
        public const int STAGE_MEDIUM = 2;
        public const int STAGE_HARD = 3;

        public int stage
        {
            get;
            private set;
        }
        private List<long> responsetimes;
        
        public CheckResponsivenessWorker(int stage, RunWorkerCompletedEventHandler completeHandler)
        {
            this.WorkerSupportsCancellation = true;
            this.WorkerReportsProgress = true;
            this.responsetimes = new List<long>();
            this.stage = stage;
            switch (stage)
            {
                case STAGE_BEST:
                    this.DoWork += new DoWorkEventHandler(this.stage_best);
                    break;
                case STAGE_MEDIUM:
                    this.DoWork += new DoWorkEventHandler(this.stage_medium);
                    break;
                case STAGE_HARD:
                    this.DoWork += new DoWorkEventHandler(this.stage_hard);
                    break;
            }
            this.RunWorkerCompleted += completeHandler;
        }

        private void stage_best(object sender, DoWorkEventArgs e)
        {
            this.responsetimes.Clear();
            Stopwatch mainWatch = new Stopwatch();
            mainWatch.Start();
            while (mainWatch.ElapsedMilliseconds<5000)
            {
                Stopwatch innerWatch = new Stopwatch();
                innerWatch.Start();
                while (innerWatch.ElapsedMilliseconds == 0);
                this.responsetimes.Add(innerWatch.ElapsedMilliseconds);
                if (this.CancellationPending) break;
            }
            long sumResponseTimes = 0;
            foreach (long responsetime in this.responsetimes) sumResponseTimes += responsetime;
            double meanResponseTimes = (double)sumResponseTimes / (double)responsetimes.Count;
            e.Result = meanResponseTimes;
        }

        private void stage_medium(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw1 = new BackgroundWorker();
            bw1.WorkerReportsProgress = false;
            bw1.WorkerSupportsCancellation = true;
            bw1.DoWork += new DoWorkEventHandler(this.stage_medium_workerRecursive);
            bw1.RunWorkerAsync();
            BackgroundWorker bw2 = new BackgroundWorker();
            bw2.WorkerReportsProgress = false;
            bw2.WorkerSupportsCancellation = true;
            bw2.DoWork += new DoWorkEventHandler(this.stage_medium_workerFiles);
            bw2.RunWorkerAsync();
            this.responsetimes.Clear();
            Stopwatch mainWatch = new Stopwatch();
            mainWatch.Start();
            while (mainWatch.ElapsedMilliseconds < 5000)
            {
                Stopwatch innerWatch = new Stopwatch();
                innerWatch.Start();
                while (innerWatch.ElapsedMilliseconds == 0) ;
                this.responsetimes.Add(innerWatch.ElapsedMilliseconds);
                if (this.CancellationPending) break;
            }
            bw1.CancelAsync();
            bw2.CancelAsync();
            long sumResponseTimes = 0;
            foreach (long responsetime in this.responsetimes) sumResponseTimes += responsetime;
            double meanResponseTimes = (double)sumResponseTimes / (double)responsetimes.Count;
            e.Result = meanResponseTimes;
        }

        private void stage_medium_workerRecursive(object sender, DoWorkEventArgs e)
        {
            for (long i = 0; i <= 1000; i++)
            {
                if (((BackgroundWorker)sender).CancellationPending) return;
                this.stage_medium_workerRecursiveTask(i, sender);
            }
        }

        private long stage_medium_workerRecursiveTask(long a, object sender)
        {
            if (((BackgroundWorker)sender).CancellationPending) return 0;
            if (a <= 0) return 0;
            else if (a == 1) return 1;
            else return this.stage_medium_workerRecursiveTask(a - 1, sender) + this.stage_medium_workerRecursiveTask(a - 2, sender);
        }

        private void stage_medium_workerFiles(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (((BackgroundWorker)sender).CancellationPending) return;
                FileStream stream = File.Create(AppDomain.CurrentDomain.BaseDirectory.ToString() + "/tmp_myfile.txt");
                for (int i = 0; i<1024; i++)
                {
                    Random rnd = new Random();
                    Byte[] b = new Byte[1024];
                    rnd.NextBytes(b);
                    stream.Write(b,0,1024);
                    stream.Flush();
                }
                stream.Close();
                File.Delete(AppDomain.CurrentDomain.BaseDirectory.ToString() + "/tmp_myfile.txt");
            }
        }

        private void stage_hard(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw1 = new BackgroundWorker();
            bw1.WorkerReportsProgress = false;
            bw1.WorkerSupportsCancellation = true;
            bw1.DoWork += new DoWorkEventHandler(this.stage_hard_workerGUI);
            bw1.RunWorkerAsync();
            this.responsetimes.Clear();
            Stopwatch mainWatch = new Stopwatch();
            mainWatch.Start();
            while (mainWatch.ElapsedMilliseconds < 5000)
            {
                Stopwatch innerWatch = new Stopwatch();
                innerWatch.Start();
                while (innerWatch.ElapsedMilliseconds == 0) ;
                this.responsetimes.Add(innerWatch.ElapsedMilliseconds);
                if (this.CancellationPending) break;
            }
            bw1.CancelAsync();
            long sumResponseTimes = 0;
            foreach (long responsetime in this.responsetimes) sumResponseTimes += responsetime;
            double meanResponseTimes = (double)sumResponseTimes / (double)responsetimes.Count;
            e.Result = meanResponseTimes;
        }

        private void stage_hard_workerGUI(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (((BackgroundWorker)sender).CancellationPending) return;
                Form newform = new Form();
                newform.Activate();
                newform.Close();
                newform.Dispose();
            }
        }
    }
}
